/**
 * Copyright 2019-2020 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "graph_optimizer/op_compiler/tbe_json_parse.h"
#include <fstream>
#include <memory>
#include <nlohmann/json.hpp>
#include <utility>
#include "common/fe_log.h"
#include "common/fe_utils.h"
#include "common/util/json_util.h"
#include "graph/debug/ge_attr_define.h"
#include "graph/op_kernel_bin.h"
#include "graph/utils/attr_utils.h"
#include "runtime/mem.h"
#include "tensor_engine/fusion_api.h"

using nlohmann::json;

namespace fe {
static const std::string JSON_PARAM_COMPRESS_PARAMETERS = "compress_parameters";
static const std::string JSON_PARAM_WEIGHT_REPEAT = "weight_repeat";
const int32_t kMaxBlockDim = 65535;
using JsonExpcetion = nlohmann::json::exception;

TbeJsonFileParse::~TbeJsonFileParse() {}

/*
*  @ingroup fe
*  @brief  parse the block_dim info in handle
*  @param   [in] handle
*  @param   [out] op_desc_ set block_dim according to the block_dim info in handle
*  @return SUCCESS or FAILED
*/
Status TbeJsonFileParse::ParseTvmBlockDim(const JsonHandle handle) {
  const json *j = static_cast<json*>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmBlkDim] json is nullptr."), return FAILED);
  int32_t block_dim;
  try {
    block_dim = (j->find("blockDim") == j->end()) ? 1 : static_cast<int32_t>(j->at("blockDim"));
    if (((block_dim) < -1) || (block_dim > kMaxBlockDim)) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmBlkDim] blockDim[%d] is out of range, range is (-1, 65535).",
                      block_dim);
      return FAILED;
    }

    if (block_dim == -1) {
      block_dim = 1;
    }
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmBlkDim] get the blockDim failed, exception:%s.", e.what());
    return FAILED;
  }
  ge::AttrUtils::SetInt(op_desc_, ge::TVM_ATTR_NAME_BLOCKDIM, block_dim);
  FE_LOGD("ParseTvmBlockDim: %u %s", block_dim, op_desc_->GetName().c_str());
  return SUCCESS;
}

/*
*  @ingroup fe
*  @brief  parse the batch_bind_only info in handle
*  @param   [in] handle
*  @param   [out] op_desc_ set batch_bind_only according to
*  the batch_bind_only info in handle
*  @return SUCCESS or FAILED
*/
Status TbeJsonFileParse::ParseBatchBindOnly(const JsonHandle handle) {
  const json *json_file = static_cast<json*>(handle);
  FE_CHECK(json_file == nullptr,
           REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseBtcBindOnly] json is nullptr."), return FAILED);
  uint32_t batch_bind_only;
  try {
    batch_bind_only = (json_file->find("batchBindOnly") == json_file->end())
                          ? 0
                          : static_cast<uint32_t>(json_file->at("batchBindOnly"));
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseBtcBindOnly] get the batch_bind_only failed, exception:%s.",
                    e.what());
    return FAILED;
  }

  FE_LOGD("Parse batch_bind_only[%u] from node [%s].", batch_bind_only, op_desc_->GetName().c_str());
  if (!ge::AttrUtils::SetBool(op_desc_, ge::ATTR_N_BATCH_SPILT, batch_bind_only)) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseBtcBindOnly] Set attr _is_n_batch_split for node[%s] failed.",
                    op_desc_->GetName().c_str());
    return FAILED;
  }
  return SUCCESS;
}

/*
*  @ingroup fe
*  @brief parse the magic info in handle
*  @param   [in] handle
*  @param   [out] op_desc_ set magic according to magic info in handle
*  @return SUCCESS or FAILED
*/
Status TbeJsonFileParse::ParseTvmMagic(const JsonHandle handle) {
  const json *j = static_cast<json*>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmMgc] json is nullptr."), return FAILED);
  std::string magic;
  try {
    // check magic key value
    if (j->find("magic") == j->end()) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmMgc] Data error! 'magic' is necessary.");
      return FAILED;
    }
    json j_magic = j->at("magic");
    magic = j_magic.get<std::string>();
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmMgc] get the magic failed, exception:%s.", e.what());
    return FAILED;
  }

  if (magic != "RT_DEV_BINARY_MAGIC_ELF_AICPU" && magic != "RT_DEV_BINARY_MAGIC_ELF" &&
      magic != "RT_DEV_BINARY_MAGIC_ELF_AIVEC" && magic != "RT_DEV_BINARY_MAGIC_ELF_AICUBE") {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmMgc] The magic value[%s] is not valid.", magic.c_str());
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmMgc] Only support \
                    RT_DEV_BINARY_MAGIC_(ELF_AICPU/ELF/ELF_AIVEC/ELF_AICUBE).");
    return FAILED;
  }

  ge::AttrUtils::SetStr(op_desc_, ge::TVM_ATTR_NAME_MAGIC, magic);

  return SUCCESS;
}

Status TbeJsonFileParse::ParseTvmCoreType(const JsonHandle handle) {
  const json *j = static_cast<json*>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmCoreType] json is nullptr."), return FAILED);

  std::string core_type;
  try {
    // check core_type key value, NOT required
    if (j->find("core_type") == j->end()) {
      return SUCCESS;
    }

    json j_core_type = j->at("core_type");
    core_type = j_core_type.get<std::string>();
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmCoreType] get the core_type failed, exception:%s.", e.what());
    return FAILED;
  }

  if ((core_type != "AIC" && core_type != "AIV")) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmCoreType] Data error! 'core_type' should be AIC or AIV.");
    return FAILED;
  }

  ge::AttrUtils::SetStr(op_desc_, ATTR_NAME_CUBE_VECTOR_CORE_TYPE, core_type);

  return SUCCESS;
}

Status TbeJsonFileParse::ParseTvmKernelList(const JsonHandle handle) {
  const json *j = static_cast<json*>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmKernList] json is nullptr."), return FAILED);

  if (j->find("kernelList") != j->end()) {
    try {
      json kernel_list = j->at("kernelList");
      if (kernel_list.empty()) {
        FE_LOGD("kernel list of node[%s] is empty.", op_desc_->GetName().c_str());
        return SUCCESS;
      }
      try {
        json first_name = kernel_list.begin()->at("kernelName");
        std::string kernel_list_first = first_name.get<std::string>();
        FE_LOGI("kernel list first node name is %s.", kernel_list_first.c_str());
        ge::AttrUtils::SetStr(op_desc_, ATTR_NAME_KERNEL_LIST_FIRST_NAME, kernel_list_first);
      } catch (const JsonExpcetion &e) {
        REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmKernList] ParseTvmKernelList get kernelName Exception:%s.",
                        e.what());
        }
    } catch (const JsonExpcetion &e) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmKernList] ParseTvmKernelList get kernelList Exception:%s.",
                      e.what());
      }
  }
  return SUCCESS;
}

int32_t TransGeWorkspaceType(int32_t type) {
  int32_t res_type = 0;
  switch (type) {
    case te::TBE_MEMORY_DDR:
      res_type = RT_MEMORY_HBM;
      break;

    case te::TBE_MEMORY_L1:
      res_type = RT_MEMORY_L1;
      break;

    case te::TBE_MEMORY_L2:
      res_type = RT_MEMORY_L2;
      break;

    default:
      res_type = RT_MEMORY_HBM;
      break;
  }
  return res_type;
}

/* OpKernelBinPtr
 *  @ingroup fe
 *  @brief  parse the workspace info in handle
 *  @param   [in] handle
 *  @param   [out] op_desc_, tvm_workspace_sizes_  set workspace according to
 * block_dim info in handle
 *  @return SUCCESS or FAILED
 */
Status TbeJsonFileParse::ParseTvmWorkSpace(const JsonHandle handle) {
  const json *j = static_cast<json *>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmWorkSpace] json is nullptr."), return FAILED);
  if (j->find("workspace") == j->end()) {
    return SUCCESS;
  }

  std::vector<int32_t> tvm_workspace_types;
  try {
    json j_workspace = j->at("workspace");

    // make sure that both num and size exist
    if ((j_workspace.find("num") == j_workspace.end() || j_workspace.find("size") == j_workspace.end())) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmWorkSpace] Data error! 'num', 'size' and 'type' are \
                      necessary.");
      return FAILED;
    }

    // get number of workspace
    uint32_t workspace_num = j_workspace.at("num").get<uint32_t>();

    // get size and type of workspace
    json j_workspace_sizes = j_workspace.at("size");

    if (!j_workspace_sizes.is_array()) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmWorkSpace] Format error! 'size' should be array.");
      return FAILED;
    }

    if ((workspace_num != static_cast<uint32_t>(j_workspace_sizes.size()))) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmWorkSpace] Data error! 'num' is error,not equal to 'size' or \
                      'type'.");
      return FAILED;
    }

    if (j_workspace.find("type") != j_workspace.end()) {
      json j_workspace_types = j_workspace.at("type");
      if (!j_workspace_types.is_array()) {
        REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmWorkSpace] Format error! 'type' should be array.");
        return FAILED;
      }
      if (workspace_num != static_cast<uint32_t>(j_workspace_types.size())) {
        REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmWorkSpace] Data error! 'num' is error, not equal to 'type'.");
        return FAILED;
      }
      for (auto const &type : j_workspace_types) {
        tvm_workspace_types.push_back(TransGeWorkspaceType(type.get<int32_t>()));
      }
    }
    for (auto const &size : j_workspace_sizes) {
      // add 32B memory for workspace, the memory obtained from the json file is
      // not enough
      tvm_workspace_sizes_.push_back(size.get<int64_t>() + DATA_MEMORY_ALIGN_SIZE);
    }
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmWorkSpace] get the workspace failed, exception:%s.", e.what());
    return FAILED;
  }

  op_desc_->SetWorkspaceBytes(tvm_workspace_sizes_);
  if (!tvm_workspace_types.empty()) {
    ge::AttrUtils::SetListInt(op_desc_, ge::TVM_ATTR_NAME_WORKSPACE_TYPE, tvm_workspace_types);
  }
  return SUCCESS;
}

/*
*  @ingroup fe
*  @brief  parse the parameters info in handle
*  @param   [in] handle
*  @param   [out] op_desc_, set output_index and workspace
*  according to parameters info in handle
*  @return SUCCESS or FAILED
*/
Status TbeJsonFileParse::ParseTvmParameters(const JsonHandle handle) {
  const json *j = static_cast<json*>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmParm] json is nullptr."), return FAILED);
  if (j->find("parameters") == j->end()) {
    return SUCCESS;
  }

  std::vector<int64_t> parameters_index;
  try {
    json j_parameters = j->at("parameters");

    if (!j_parameters.is_array()) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmParm] Format error! 'parameters' should be array.");
      return FAILED;
    }

    // get parameters value
    for (auto it = j_parameters.begin(); it != j_parameters.end(); ++it) {
      json flag = *it;
      parameters_index.push_back(flag.get<int64_t>());
    }
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmParm] get the parameters failed, exception:%s.", e.what());
    return FAILED;
  }

  return SetAtomicInfo(parameters_index);
}

void TbeJsonFileParse::GetWorkspaceAtomicFlagAndOutputIndexFlag(const std::vector<int64_t> &parameters_index,
                                                                const size_t &workspace_num,
                                                                const size_t &input_num, const size_t &output_num,
                                                                std::vector<int64_t> &output_index,
                                                                int64_t &workspace_atomic_flag,
                                                                bool &output_index_flag) {
  size_t parameters_index_size = parameters_index.size();
  for (size_t i = 0; i < workspace_num; ++i) {
    size_t index = input_num + output_num + i;
    if (index >= parameters_index_size) {
        continue;
    }
    if (parameters_index[index] == 1) {
      workspace_atomic_flag = 1;
      break;
    }
  }
  for (size_t i = 0; i < output_num; ++i) {
    size_t index = input_num + i;
    if (index >= parameters_index_size) {
        continue;
    }
    output_index.push_back(parameters_index[index]);
    if (parameters_index[index] != 0) {
      output_index_flag = true;
    }
  }
}

Status TbeJsonFileParse::SetAtomicInfo(std::vector<int64_t> &parameters_index) {
  // need modify
  std::vector<int64_t> output_index;
  int64_t workspace_atomic_flag = 0;
  size_t input_num = op_desc_->GetInputsSize();
  size_t workspace_num = op_desc_->GetWorkspaceBytes().size();
  size_t output_num = op_desc_->GetOutputsSize();
  size_t total_size = input_num + output_num + workspace_num;
  bool is_support_unknown_shape = false;
  if (ge::AttrUtils::GetBool(op_desc_, STR_SUPPORT_DYNAMIC_SHAPE, is_support_unknown_shape) &&
      is_support_unknown_shape) {
    total_size = input_num + workspace_num + output_num + 1;
  }
  if (total_size >= parameters_index.size()) {
    size_t loss_num = total_size - parameters_index.size();
    for (size_t i = 0; i < loss_num; ++i) {
      parameters_index.push_back(0);
    }
    ge::AttrUtils::SetListInt(op_desc_, "ub_atomic_params", parameters_index);
  } else {
    FE_LOGD("parameters size is larger than input&output&workspace.");
    FE_LOGD("inputNum:%zu, output_num:%zu, workspaceSize:%zu, para_size:%zu name:%s", input_num, output_num,
            workspace_num, parameters_index.size(), op_desc_->GetName().c_str());
    ge::AttrUtils::SetListInt(op_desc_, "ub_atomic_params", parameters_index);
    return SUCCESS;
  }
  // in parameters data sort as input->output->workspace
  bool output_index_flag = false;
  GetWorkspaceAtomicFlagAndOutputIndexFlag(parameters_index, workspace_num, input_num, output_num,
                                           output_index, workspace_atomic_flag, output_index_flag);

  ge::AttrUtils::SetInt(op_desc_, TBE_OP_ATOMIC_WORKSPACE_FLAG, workspace_atomic_flag);

  if (output_index_flag) {
    ge::AttrUtils::SetListInt(op_desc_, TBE_OP_ATOMIC_OUTPUT_INDEX, output_index);
  }
  return SUCCESS;
}

/*
*  @ingroup fe
*  @brief  parse the meta_data info in handle
*  @param   [in] handle
*  @param   [out] op_desc_, set meta_data according to meta_data info in handle
*  @return SUCCESS or FAILED
*/
Status TbeJsonFileParse::ParseTvmMetaData(const JsonHandle handle) {
  // 1. get bin_file_suffix
  std::string binfile_suffix = GetStrValueFromJson(handle, "binFileSuffix");

  // do not register MetaData when bin_file_suffix is not .so
  if (binfile_suffix != ".so") {
    FE_LOGD("'BinFileSuffix' is not '.so', skip.");
    return SUCCESS;
  }

  // 2. get bin_file_name
  std::string binfile_name = GetStrValueFromJson(handle, "binFileName");
  // check kernel name
  if (binfile_name.empty()) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmMetaData] BinFileName is empty. please check json file.");
    return FAILED;
  }

  // sha256, set sha256 to be null string when it is not specifed in json file
  std::string sha256 = GetStrValueFromJson(handle, "sha256");
  if (sha256.empty()) {
    REPORT_FE_ERROR(
        "[SubGraphOpt][ParseJson][ParseTvmMetaData] BinFileSuffix is so but json info is not "
        "enough. please check json file.");
    return FAILED;
  }

  // 3. concat meta data
  std::string meta_data;
  meta_data.append(binfile_name);
  meta_data.append(binfile_suffix);
  meta_data.append(", version, ");
  meta_data.append(sha256);
  meta_data.append(", shared");
  FE_LOGD("Add meta data: %s.", meta_data.c_str());
  ge::AttrUtils::SetStr(op_desc_, ge::TVM_ATTR_NAME_METADATA, meta_data);

  return SUCCESS;
}

/*
*  @ingroup fe
*  @brief  parse the kernel_name info in handle
*  @param   [in] handle
*  @param   [out] op_desc_, add kernel_name to op_desc_.name according to
* kernel_name info in handle
*  @return SUCCESS or FAILED
*/
Status TbeJsonFileParse::ParseTvmKernelName(const JsonHandle handle) {
  std::string kernel_name = GetStrValueFromJson(handle, "kernelName");
  // 校验kernel name
  if (kernel_name.empty()) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmKernNm] KernelName is empty. please check json file.");
    return FAILED;
  }

  ge::AttrUtils::SetStr(op_desc_, op_desc_->GetName() + "_kernelname", kernel_name);
  return SUCCESS;
}

Status TbeJsonFileParse::ParseConvCompressParameters(const JsonHandle handle) {
  const json *j = static_cast<json*>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmKernNm] json is nullptr."), return FAILED);
  if (j->find(JSON_PARAM_COMPRESS_PARAMETERS) == j->end()) {
    return SUCCESS;
  }

  std::vector<int64_t> compress_param_vec;
  try {
    json json_compress = j->at(JSON_PARAM_COMPRESS_PARAMETERS);
    if (!json_compress.is_array()) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmKernNm] Format error! compress_parameters should be array.");
      return FAILED;
    }

    for (auto it = json_compress.begin(); it != json_compress.end(); it++) {
      json flag = *it;
      compress_param_vec.push_back(flag.get<int64_t>());
    }
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmKernNm] get the compress_parameters failed, exception:%s.",
                    e.what());
    return FAILED;
  }

  if (!ge::AttrUtils::SetListInt(op_desc_, ATTR_NAME_COMPRESS_PARAMETERS, compress_param_vec)) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseTvmKernNm] Fail to set attr compress_weight for node[%s].",
                    op_desc_->GetName().c_str());
    return FAILED;
  }

  return SUCCESS;
}

Status TbeJsonFileParse::ParseWeightRepeat(const JsonHandle handle) {
  const json *j = static_cast<json *>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseWgtRepeat] json is nullptr."), return FAILED);
  if (j->find(JSON_PARAM_WEIGHT_REPEAT) == j->end()) {
    return SUCCESS;
  }

  try {
    json json_weight_repeat = j->at(JSON_PARAM_WEIGHT_REPEAT);
    int64_t weight_repeat = json_weight_repeat.get<int64_t>();
    FE_LOGI("The weight repeat of node[%s] is %u", op_desc_->GetName().c_str(), weight_repeat);
    if (!ge::AttrUtils::SetInt(op_desc_, ATTR_NAME_WEIGHT_REPEAT, weight_repeat)) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseWgtRepeat] Fail to set attr weight_repeat for node[%s].",
                      op_desc_->GetName().c_str());
      return FAILED;
    }
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseWgtRepeat] get the weight_repeat failed, exception:%s.", e.what());
    return FAILED;
  }
  return SUCCESS;
}

Status TbeJsonFileParse::ParseOpParaSize(const JsonHandle handle) {
  const json *j = static_cast<json *>(handle);
  FE_CHECK(j == nullptr, REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseOpParaSize] json is nullptr."), return FAILED);
  uint32_t op_para_size;
  try {
    op_para_size = (j->find("opParaSize") == j->end()) ? 0 : (uint32_t)j->at("opParaSize");
  } catch (const JsonExpcetion &e) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ParseOpParaSize] get the opParaSize failed, exception:%s.", e.what());
    return FAILED;
  }
  ge::AttrUtils::SetInt(op_desc_, OP_PARA_SIZE, (int64_t)op_para_size);
  FE_LOGD("ParseOpParaSize: %u %s", op_para_size, op_desc_->GetName().c_str());
  return SUCCESS;
}

/*
*  @ingroup fe
*  @brief  get the str value from handle based on key
*  @param   [in] handle, key
*  @return j->at(key)
*/
std::string TbeJsonFileParse::GetStrValueFromJson(const JsonHandle handle, const std::string& key) {
  const json *j = static_cast<json*>(handle);
  FE_CHECK(j == nullptr, FE_LOGD("json is nullptr."), return "");
  if (j->find(key) == j->end()) {
    return "";
  }

  try {
    return j->at(key);
  } catch (const JsonExpcetion &e) {
    FE_LOGD("get the %s failed, exception:%s.", key.c_str(), e.what());
  }
  return "";
}

/*
*  @ingroup fe
*  @brief  joint the path of bin file, if success, renew the op_desc.name
*  @param   [in] handle
*  @param   [out] op_desc_->name
*  @return  SUCCESS or FAILED
*/
Status TbeJsonFileParse::PackageTvmBinFile(const JsonHandle handle) {
  // 拼接bin file路径
  std::string binfile_suffix = GetStrValueFromJson(handle, "binFileSuffix");
  std::string binfile_name = GetStrValueFromJson(handle, "binFileName");

  if (binfile_suffix.empty() || binfile_name.empty()) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][PkgTvmBinFile] BinFileName or binfile_suffix is empty. please \
                    check json file.");
    return FAILED;
  }

  std::string bin_file_path = tvm_file_path_;
  bin_file_path.append("/");
  bin_file_path.append(binfile_name);
  bin_file_path.append(binfile_suffix);

  vector<char> buffer;
  bool ret = ReadBytesFromBinaryFile(bin_file_path, buffer);
  if (ret != SUCCESS) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][PkgTvmBinFile] Read bin file failed, file path is %s.",
                    bin_file_path.c_str());
    return PARAM_INVALID;
  }

  std::string key = op_desc_->GetName();

  ge::OpKernelBinPtr tbe_kernel_ptr = std::make_shared<ge::OpKernelBin>(key, std::move(buffer));
  FE_CHECK(tbe_kernel_ptr == nullptr,
           REPORT_FE_ERROR("[SubGraphOpt][ParseJson][PkgTvmBinFile] tbeKernelPtr is nullptr."), return FAILED);
  op_desc_->SetExtAttr(ge::OP_EXTATTR_NAME_TBE_KERNEL, tbe_kernel_ptr);
  ge::AttrUtils::SetStr(op_desc_, ge::ATTR_NAME_TBE_KERNEL_NAME, tbe_kernel_ptr->GetName());
  FE_LOGD("node[%s]'s tbe kernel name is %s.", op_desc_->GetName().c_str(), tbe_kernel_ptr->GetName().c_str());
  ge::Buffer tbe_kernel_buffer(tbe_kernel_ptr->GetBinDataSize());
  tbe_kernel_buffer = ge::Buffer::CopyFrom(tbe_kernel_ptr->GetBinData(), tbe_kernel_ptr->GetBinDataSize());
  ge::AttrUtils::SetBytes(op_desc_, ge::ATTR_NAME_TBE_KERNEL_BUFFER, tbe_kernel_buffer);
  size_t tbe_kernel_size;
  tbe_kernel_size = tbe_kernel_ptr->GetBinDataSize();
  ge::AttrUtils::SetInt(op_desc_, ATTR_NAME_TBE_KERNEL_SIZE, tbe_kernel_size);
  FE_LOGD("node[%s]'s tbe kernel buffer size is %lu.", op_desc_->GetName().c_str(), tbe_kernel_buffer.GetSize());
  return SUCCESS;
}

void TbeJsonFileParse::SetTvmFilePath(const TbeJsonInfo& info) {
  tvm_file_path_ = ".";
  string bin_file_path;
  if (!info.bin_file_path.empty()) {
    bin_file_path = info.bin_file_path;
  } else {
    bin_file_path = info.json_file_path;
  }
  size_t find_pos = bin_file_path.find_last_of("\\/");
  if (find_pos != std::string::npos) {
    tvm_file_path_ = bin_file_path.substr(0, find_pos);
  }
}
/*
*  @ingroup fe
*  @brief   package the json info together
*  @param   [in]  info
*  @param   [out] tvm_file_path_
*  @return  SUCCESS or FAILED
*/
Status TbeJsonFileParse::PackageTvmJsonInfo(const TbeJsonInfo& info) {
  json j;
  FE_LOGD("Sart to parse op_json_file %s", info.json_file_path.c_str());
  if (ReadJsonFile(info.json_file_path, j) != SUCCESS) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][PkgTvmJsInfo] ReadJsonFile failed.");
    return FAILED;
  }

  SetTvmFilePath(info);

  for (auto &parseFunc : parseFuncMap) {
    if ((this->*(parseFunc.second))(&j) != SUCCESS) {
      REPORT_FE_ERROR("[SubGraphOpt][ParseJson][PkgTvmJsInfo] Parse %s failed, the json file:%s.",
                      parseFunc.first.c_str(), info.json_file_path.c_str());
      return FAILED;
    }
  }
  return SUCCESS;
}

/*
*  @ingroup fe
*  @brief   reading binary files
*  @param   [in]  file_name(or path), buffer, length
*  @param   [out] length
*  @return  SUCCESS or FAILED
*/
Status TbeJsonFileParse::ReadBytesFromBinaryFile(const string& file_name, std::vector<char>& buffer) {
  if ((file_name.empty())) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ReadBFromBinFile] incorrect parameter. file path is null");
    return FAILED;
  }

  string real_path = RealPath(file_name.c_str());
  if (real_path.empty()) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ReadBFromBinFile] file path '%s' not valid.", file_name.c_str());
    return FAILED;
  }

  std::ifstream file(real_path.c_str(), std::ios::binary | std::ios::ate);
  if (!file.is_open()) {
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ReadBFromBinFile] read file %s failed.", file_name.c_str());
    return FAILED;
  }

  std::streamsize size = file.tellg();

  if (size <= 0) {
    file.close();
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ReadBFromBinFile] file length <= 0, not valid.");
    return FAILED;
  }

  if (size > MAX_FILE_SIZE_LIMIT) {
    file.close();
    REPORT_FE_ERROR("[SubGraphOpt][ParseJson][ReadBFromBinFile] File size %ld is out of limit: %d.",
                    size, MAX_FILE_SIZE_LIMIT);
    return FAILED;
  }

  file.seekg(0, std::ios::beg);

  buffer.resize(size);
  file.read(&buffer[0], size);
  file.close();
  FE_LOGD("Read size:%ld", size);
  return SUCCESS;
}
}  // namespace fe
